# -*- coding: utf-8 -*-
# Python 2.7
# Pattern based natural language processing tools for Estonian.
# Copyright (C) 2013 University of Tartu
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from pandas import Series, DataFrame
from patnlp import *
from itertools import izip
import re

def regex_doc_cover(doc, series_name, pattern):
    '''Given a series of words and a regular expression, create an
    OrderedDocCover instance.'''
    words  = list(doc[series_name])
    words2 = []
    for word in words:
        try:
            words2.append(unicode(word))
        except UnicodeDecodeError:
            words2.append(unicode(word, 'utf-8'))
    words = words2
    idxs  = []
    for idx, word in enumerate(words):
        if idx > 0:
            idxs.append(idx)
        idxs.extend([idx]*len(word))
    s = u' '.join(words)
    cover = set()
    for mg in re.finditer(pattern, s, re.UNICODE):
        for idx in range(mg.start(), mg.end()):
            cover.add(idxs[idx])
    return OrderedDocCover(len(words), LongVector(list(frozenset(cover))))

def regex_cover(corpus, series_name, pattern):
    '''Given a corpus, series name and a regex pattern, create
       an OrderedCover instance.'''
    cover = OrderedCover()
    for doc_id in corpus.keys():
        odc = regex_doc_cover(corpus[doc_id], series_name, pattern)
        cover.add_doc_cover(doc_id, odc)
    return cover

def context_doc_cover(doc, series_name, pattern, radius):
    ordc  = regex_doc_cover(doc, series_name, pattern)
    n = len(doc[series_name])
    indices = LongVector([i for pos in ordc.indices()
        for i in range(max(pos-radius, 0), min(pos+radius+1, n))])
    return OrderedDocCover(n, indices)

def context_cover(corpus, series_name, pattern, radius):
    '''Extract a context cover from a corpus series around positions matching
    the given pattern.'''
    cover = OrderedCover()
    for doc_id in corpus.keys():
        odc = context_doc_cover(corpus[doc_id], series_name, pattern, radius)
        cover.add_doc_cover(doc_id, odc)
    return cover

def doc_cover_series(doccover, matchval=True, nomatchval=False):
    '''Create a Series from a doccover. Each element will be replaced
       by `matchval` and each non-element (a negative) by `nomatchval`'''
    bitc = BitsetDocCover(doccover)
    series = []
    for bit in bitc.bits():
        if bit:
            series.append(matchval)
        else:
            series.append(nomatchval)
    return Series(series)

def cover_series(cover, matchval=True, nomatchval=False):
    '''Create a Series from a cover. Each element will be replaced
       by `matchval` and each non-element (a negative) by `nomatchval`
       
       Results are stored in a dict, where keys are document names.
       '''
    res = {}
    for docname in cover:
        res[docname] = doc_cover_series(cover[docname], matchval, nomatchval)
    return res

def cover_doc_values(doc, series_name, doccover):
    assert (doc.shape[0] == doccover.doc_size())
    series = doc[series_name]
    values = []
    for pos in doccover.indices():
        values.append((pos, series[pos]))
    return values

def cover_values(corpus, series_name, cover):
    '''Given a corpus, cover and series name, return the values
       in the series names.'''
    values = {}
    for docname in cover.names():
        values[docname] = cover_doc_values(corpus[docname], series_name, cover.doc_cover(docname))
    return values

def cover_html(corpus, series_name, cover):
    html = '<html><head><meta charset="utf-8"/><body>\n'
    values = cover_values(corpus, series_name, cover)
    for docname in values:
        words = list(corpus[docname][series_name])
        for pos, _ in values[docname]:
            words[pos] = '<b>' + words[pos] + '</b>'
        html += '<br><i>' + docname + '</i><p>' + u' '.join(words) + '</p>\n'
    html += '</body></html>'
    return html
